package interactor;

import context.*;
	
import mainFrame.MainFrame;
import mainFrame.DrawPanel;

import java.awt.Graphics2D;
import java.awt.Cursor;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.InputEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.ImageObserver;

import javax.swing.JOptionPane;

import object2D.Object2D;
import util.PixelPoint;
import util.UTM32Location;
import util.Util2;

// ********************************************************************
// *** CLASS: Interactor
// ********************************************************************
public abstract class Interactor implements KeyListener,MouseListener,MouseMotionListener,Context.Constants
{ //private static final boolean DEBUG=true; // Overriding Context.Constants.DEBUG
  static final String TAG="interactor.Interactor";

  public static final int MEASURE=0;   // Mouse-mode: Measuring Distance by pointing (mouse down) and dragging a rectangle.
  public static final int EDIT=1;      // Mouse-mode: Editing.
  public static final int DRAW_LINE=2; // Mouse-mode: Draw a Line by pointing (mouse down) and dragging.
  public static final int DRAW_POLYGON=3; // Mouse-mode: Draw a Polygon by repetive pointing (mouse click).
  public static final int DRAW_ELLIPSE=4; // Mouse-mode: Draw a ...
  public static final int DRAW_PARALLELOGRAM=5; // Mouse-mode: Draw a ...
  public static final int DRAW_PATH=6; // Mouse-mode: Draw a ...
  public static final int DRAW_TEXT=7; // Mouse-mode: Draw a ...
  public abstract String getMouseModeMnemonic();
  
  protected DrawPanel drawPanel;

  private int mouseMode; // The current mouse functional mode.
  protected PixelPoint mouseStart,mouseCurrent;

  private double getX(MouseEvent e) { return(e.getX()/drawPanel.getCurrentScale()); }
  private double getY(MouseEvent e) { return(e.getY()/drawPanel.getCurrentScale()); }


  // ******************************************************************
  // *** CONSTRUCTOR: Interactor
  // ******************************************************************
  public Interactor(DrawPanel drawPanel,int mouseMode)
  { this.drawPanel=drawPanel;
    this.mouseMode=mouseMode;
    this.mouseCurrent=new PixelPoint(0,0);
  }
    
  // ******************************************************************
  // *** METHOD: getMouseMode
  // ******************************************************************
  public int getMouseMode()
  { return(mouseMode); }

  // ******************************************************************
  // *** METHOD: paintMouseEffect
  // ******************************************************************
  public abstract void paintMouseEffect(Graphics2D g,ImageObserver imageObserver);


  // ******************************************************************
  // *** METHOD: measurementDone
  // ******************************************************************
  protected void measurementDone(PixelPoint p1,PixelPoint p2)
  { UTM32Location loc1=p1.toUTM32Location(drawPanel.getObjectModel().getGrid());
    UTM32Location loc2=p2.toUTM32Location(drawPanel.getObjectModel().getGrid());
	double dist=Util2.round(loc1.getDistanceInMeter(loc2),100);
    if(dist>0.1) JOptionPane.showMessageDialog(null,"DISTANCE: "+dist+" meter");
  }

  // ******************************************************************
  // *** METHOD: drawObjectDone
  // ******************************************************************
  protected void drawObjectDone(Object2D obj,String id)
  { int result=JOptionPane.showConfirmDialog(null,"DRAW "+id+": DONE\n Edit Attributes ?"
      		  ,"Add "+obj.getClassName(),JOptionPane.YES_NO_OPTION);
    drawPanel.getObjectModel().addChild(obj);
    if(result==JOptionPane.YES_OPTION) obj.edit();
  }

  
  // ******************************************************************
  // *** METHOD: keyTyped
  // ******************************************************************
  // Invoked when a key has been typed (key press is followed by a key release).
  public void keyTyped(KeyEvent e) {}

  // ******************************************************************
  // *** METHOD: keyPressed
  // ******************************************************************
  // Invoked when a key has been pressed.
  public void keyPressed(KeyEvent e) {}

  // ******************************************************************
  // *** METHOD: keyReleased
  // ******************************************************************
  // Invoked when a key has been released.
  public void keyReleased(KeyEvent e) {}

  // ******************************************************************
  // *** METHOD: mouseDragged
  // ******************************************************************
  // Invoked when a mouse button is pressed and then dragged.
  public void mouseDragged(MouseEvent e)
  { mouseCurrent.setX(getX(e));
    mouseCurrent.setY(getY(e));
    MainFrame.getStatusLine().setMousePosition(drawPanel.getObjectModel().getGrid(),mouseCurrent);
    mouseDragged();
  }
  protected abstract void mouseDragged();


  // ******************************************************************
  // *** METHOD: mouseMoved
  // ******************************************************************
  // Invoked when the mouse has been moved (with no buttons down).
  private Cursor pointCursor=Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
  private Cursor crossHairCursor=Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);
  private Cursor handCursor=Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
  public void mouseMoved(MouseEvent e)
  { mouseCurrent.setX(getX(e));
    mouseCurrent.setY(getY(e));
    MainFrame.getStatusLine().setMousePosition(drawPanel.getObjectModel().getGrid(),mouseCurrent);
	Cursor oldCursor=drawPanel.getCursor();
//	Cursor newCursor=(drawPanel.withinPointMark()!=null)?crossHairCursor:pointCursor;
	Cursor newCursor=pointCursor;
	String newDescription="";
	if(drawPanel.getPointMark(mouseCurrent)!=null) newCursor=crossHairCursor;
	else
	{ Object2D obj=drawPanel.getObject(mouseCurrent);
	  if(obj!=null) { newCursor=handCursor; newDescription=obj.getIdent(); }
	}
	if(newCursor!=oldCursor)
    { drawPanel.setCursor(newCursor);
      drawPanel.repaint();
    }
	MainFrame.getStatusLine().setDescription(newDescription);
    mouseMoved();
  }
  protected abstract void mouseMoved();
  
  // ******************************************************************
  // *** METHOD: mouseEntered
  // ******************************************************************
  // Invoked when the mouse enters a component.
  public void mouseEntered(MouseEvent e) {}

  // ******************************************************************
  // *** METHOD: mouseExited
  // ******************************************************************
  // Invoked when the mouse exits a component.
  public void mouseExited(MouseEvent e) {}

  // ******************************************************************
  // *** METHOD: mouseClicked
  // ******************************************************************
  // Invoked when the mouse has been clicked on a component.
  public void mouseClicked(MouseEvent e) {}

  // ******************************************************************
  // *** METHOD: mousePressed
  // ******************************************************************
  // Invoked when a mouse button has been pressed.
  public void mousePressed(MouseEvent e)
  { PixelPoint p=new PixelPoint(getX(e),getY(e));
    if(DEBUG) Log.d(TAG,"mousePressed: at "+p);
	int flg=e.getModifiers();
    if((flg& InputEvent.BUTTON1_MASK)!=0)
         mouseLeftPressed(p);
    else mouseRightPressed(p);
  }
  protected abstract void mouseLeftPressed(PixelPoint p);
  protected abstract void mouseRightPressed(PixelPoint p);

  // ******************************************************************
  // *** METHOD: mouseReleased
  // ******************************************************************
  // Invoked when a mouse button has been released.
  public void mouseReleased(MouseEvent e)
  { PixelPoint p=new PixelPoint(getX(e),getY(e));
    if(DEBUG) Log.d(TAG,"mouseReleased: at "+p);
    int flg=e.getModifiers();
    if((flg& InputEvent.BUTTON1_MASK)!=0) mouseLeftReleased(p);
    else mouseRightReleased(p);
  }
  protected abstract void mouseLeftReleased(PixelPoint p);
  protected abstract void mouseRightReleased(PixelPoint p);
  
}